#define GAME_CPP
#include <windows.h>											// Header File For Windows
#include <stdio.h>												// Header File For Standard Input / Output
#include <stdarg.h>												// Header File For Variable Argument Routines
#include <math.h>	
#include "openglframework.h"
#include "Camera.h"
#include <gl\gl.h>												// Header File For The OpenGL32 Library
#include <gl\glu.h>												// Header File For The GLu32 Library
#include "openGLStuff.h"
#include "game.h"
#include "InputManager.h"
#include "MapManager.h"
#include <btBulletDynamicsCommon.h>

// Toggle MPF Output
#define DEBUG_MPF

// Choose camera mode
#define GAME_CAMERA
//#define DEBUG_CAMERA

// Declarations
const char8_t CGame::mGameTitle[]="Impossible3D";
CGame* CGame::sInstance=NULL;
BOOL Initialize (GL_Window* window, Keys* keys)					// Any OpenGL Initialization Goes Here
{
	initOpenGLDrawing(window,keys,0.0f, 1.0f, 0.0f);
	CGame::CreateInstance();
	CGame::GetInstance()->init();
	
	return TRUE;						
}

void CGame::init()
{
	// Init input manager singleton
	InputManagerC::CreateInstance();
	InputManagerC::GetInstance()->init();

	// Init the mapLevel1(may move to elsewhere
	MapManager::CreateInstance();
	MapManager::GetInstance()->init();
	MapManager::GetInstance()->parseMapFile("mapFile/level1.txt");
	list<trackInfoT>* myMapInfoList = MapManager::GetInstance()->getMapList();

	// Init physics system
	m_physicsHandle.Init();
	// Init lighting
	m_lightManager.Init();

	//generate the cube according to the mapList
	//m_MapObjList = new list<BaseShape*>();
	//list<trackInfoT>::iterator it;
	//for(it = myMapInfoList->begin(); it!=myMapInfoList->end(); it++)
	//{
	//	//0 for cube, 1 for pyramid, hardcode it , fix later
	//	BaseShape* _shape;
	//	switch(it->trackType)
	//	{
	//		case 0:
	//			_shape = new Cube();
	//			m_MapObjList->push_back(_shape);
	//			m_physicsHandle.AddBoxEnvironment(_shape->GetPhysicsEntity(), it->posX, it->posY, it->posZ, 0.5f*it->scaleX, 0.5f*it->scaleY, 0.5f*it->scaleZ, 0.0f);
	//			break;
	//		case 1:
	//			_shape = new Pyramid();
	//			m_MapObjList->push_back(_shape);
	//			m_physicsHandle.AddConeEnvironment(_shape->GetPhysicsEntity(), it->posX, it->posY, it->posZ, 0.5f * sqrt(0.7 * (it->scaleX) * (it->scaleZ)), 1.0f*(it->scaleY), 0.0f);
	//			break;
	//	}
	//}

	// test boxes

	m_physicsHandle.AddBoxEnvironment(m_cube1.GetPhysicsEntity(), 0, 0, -5, // position
		2, 1, 10, // dimensions
		0
		);

	m_physicsHandle.AddBoxEnvironment(m_cube2.GetPhysicsEntity(), 0, -10, -20, //position
		2, 2, 10, // dimensions
		0 // mass
		);

	m_physicsHandle.AddBoxEnvironment(m_cube3.GetPhysicsEntity(), 0, -0, -35, //position
		2, 3, 5, // dimensions
		0 // mass
		);

	// Add player rigid body
	m_physicsHandle.AddBoxPlayer((m_player.GetPhysicsEntity()), 0, 5.0f, -2.0f, 0.5f, 0.5f, 0.5f, 2.0f);
	m_player.ResetPlayer();

	//m_physicsHandle.AddBoxEnvironment(m_cube1.GetPhysicsEntity(), 0.0f, 0.0f, 0.0f, 10.0f, 1.0f, 50.0f, 0.0f);

	//m_physicsHandle.AddConeEnvironment(m_pyramid1.GetPhysicsEntity(), 0, 2.0f, -5.0f, 1.0f, 1.0f, 0.0f);
	//m_pyramid1.SetRotation(3.1415926 / 2, 1.0f, 0, 0);
	// Set handle to player's collision object
	ImpossiblePhysics::g_playerCollider = m_player.GetPhysicsEntity();

	// Set game dimension
	m_player.SetMode3D(g_bMode3D);
}

void CGame::UpdateCamera(float_t argDeltaTime)
{

#ifdef DEBUG_CAMERA

	// Update camera based on input
	if(InputManagerC::GetInstance()->IsMovingForward()) 
	{
		m_camera.MoveForward(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsMovingBackward())
	{
		m_camera.MoveBackward(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsMovingRight())
	{
		m_camera.MoveRight(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsMovingLeft())
	{
		m_camera.MoveLeft(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsMovingUp())
	{
		m_camera.MoveUp(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsMovingDown())
	{
		m_camera.MoveDown(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsRotatingYawCC())
	{
		m_camera.RotateCameraYawCC(argDeltaTime);
	}

	if(InputManagerC::GetInstance()->IsRotatingYawCW())
	{
		m_camera.RotateCameraYawCW(argDeltaTime);
	}

#endif
}

// Update scene
void CGame::UpdateFrame(float_t argDeltaTime)			
{
	// Check for view toggle
	if(InputManagerC::IsToggle())
	{
		g_bMode3D = !g_bMode3D;
		m_player.SetMode3D(g_bMode3D);
	}


#ifdef DEBUG_MPF
	char _debugString[100];
	sprintf(_debugString, "MPF:%f\n", argDeltaTime);
	OutputDebugStringA(_debugString);
#endif
//	// Update objects
#ifdef GAME_CAMERA
	m_player.Update(argDeltaTime);
#endif

	//list<BaseShape*>::iterator it;
	//for(it = m_MapObjList->begin(); it!=m_MapObjList->end(); it++)
	//{
	//	(*it)->Update(argDeltaTime);
	//}

	// Update physics system
	m_physicsHandle.Update(argDeltaTime);

	// Update input manager
	InputManagerC::GetInstance()->update(argDeltaTime);



	UpdateCamera(argDeltaTime);
}

// Draw scene
void CGame::DrawScene(void)										
{
	// Clear buffers
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if(g_bMode3D)
	{
		// Set view matrix
#ifdef DEBUG_CAMERA
		m_camera.SetLookAt();
#endif

#ifdef GAME_CAMERA
		m_player.SetLookAt();
#endif
	}

	//if(g_bMode3D)
	//{
	//	// Draw player
	//	m_player.Draw();

	//	list<BaseShape*>::iterator it;
	//	for(it = m_MapObjList->begin(); it!=m_MapObjList->end(); it++)
	//	{
	//		(*it)->Draw();
	//	}
	//}
	//else
	//{
	//	list<BaseShape*>::iterator it;
	//	for(it = m_MapObjList->begin(); it!=m_MapObjList->end(); it++)
	//	{
	//		(*it)->Draw2D();
	//	}

	//	m_player.Draw2D();
	//}


	// Draw player
	if(g_bMode3D)
	{
		m_player.Draw();
		m_cube1.Draw();
		m_cube2.Draw();
		m_cube3.Draw();
	}
	else
	{
		m_player.Draw2D();
		m_cube1.Draw2D();
		m_cube2.Draw2D();
		m_cube3.Draw2D();
	}

	//list<BaseShape*>::iterator it;
	//for(it = m_MapObjList->begin(); it!=m_MapObjList->end(); it++)
	//{
	//	(*it)->Draw();
	//}

	//list<BaseShape*>::iterator it;
	//for(it = m_MapObjList->begin(); it!=m_MapObjList->end(); it++)
	//{
	//	(*it)->Draw2D();
	//}

	//m_player.Draw2D();
}

CGame *CGame::CreateInstance()
{
	sInstance = new CGame();
	return sInstance;
}
void CGame::shutdown()
{
	//BallManagerC::GetInstance()->shutdown();
}
void CGame::DestroyGame(void)
{
/*	delete BallManagerC::GetInstance();*/
}

CGame::~CGame()
{


};